/*
* Valentine Gladstein
* SOLAR ID 108731583
* Homework #2
* CSE214
* Recitation 03-Phil Ammirato
* Grading TA: Yanjie LI
*/

import java.io.*;
import java.util.*;

public class CardList {

//The CardList class stores a series of CarDInfoNode objects in linked-list format.


    private CardInfoNode head;   //the first item in the list
    private CardInfoNode cur;    //the current item in the lsit
    private CardInfoNode tail;   // the last item in the lsit

    private int curPos;


/**       
 * Defualt constructor. 
 */ 
    public CardList() {}

/**       
 * Constructor which takes to CarDInfoNode objects as parameters and consturcts a list with them as the head ant tail, respectively.
 */ 
    public CardList(CardInfoNode first, CardInfoNode last) {
	head = first;
	tail = last;
	cur = head;
	curPos = 0;

    }


/**
 * Gets the String representation of this CardList object, neatly formatted into rows and columns
 *
 * @return Formatted String representing the current CardList object and all of the CardInfo objects it contains
 * Big-O value: O(n), because all items in the lsit must be accessed.
 */
    public String toString() {
	String result = "------------------------------------------------------------------------------------------------------------------------\n";
	result += String.format("%-25s%-14s%-10s%-s10s%-6s", "name", "company", "issued date", "balance", "status")+"\n";
	result += "------------------------------------------------------------------------------------------------------------------------\n";
	cur = head;
	curPos = 0;
	while (cur != tail) {
	    result += cur.dataToString();
	    cur = cur.getNext();
	    curPos++;
	}
	cur = head;
	curPos = 0;
	return result;
    }
    
/**
 * Inserts a new CardInfo into the lsit by wrapping it in a CarDInfoNode object.
 *
 * Big-O value: O(n), because in the worst case, all items in the lsit must be accessed.
 */
    public void insertCardInfo(CardInfo info) {
	CardInfoNode infoNode = new CardInfoNode(info);
	if (head == null){
	    head = infoNode;
	    tail = infoNode;
	    cur = infoNode;
	    curPos = 0;
	    return;
	}
	if (head.getInfo().getName().compareToIgnoreCase(info.getName()) >  0){
	    head.setPrev(infoNode);
	    infoNode.setPrev(null);
	    infoNode.setNext(head);
	    head = infoNode;
	    return;
	}
	if (tail.getInfo().getName().compareToIgnoreCase(info.getName()) < 0){
	    tail.setNext(infoNode);
	    infoNode.setNext(null);
	    infoNode.setPrev(tail);
	    tail = infoNode;
	    return;
	}
	if (cur.getInfo().getName().compareToIgnoreCase(info.getName()) >= 0){
	    cur = head;
	    curPos = 0;
	}
	while(cur.getNext() != null && cur.getNext().getInfo().getName().compareToIgnoreCase(info.getName()) < 0 ){
	    cur = cur.getNext();
	    curPos++;
	    if (cur.getNext() == null){
		cur.setNext(infoNode);
		infoNode.setNext(null);
		infoNode.setPrev(cur);
		tail = infoNode;
		return;
	    }
	}
	while((cur.getNext() != null && cur.getNext().getInfo().getName().compareToIgnoreCase(info.getName()) == 0) && (cur.getNext().getInfo().getCompany().compareToIgnoreCase(info.getCompany()) <= 0 )){
	    cur = cur.getNext();
	    curPos++;
	    if (cur.getNext() == null){
		cur.setNext(infoNode);
		infoNode.setNext(null);
		infoNode.setPrev(cur);
		tail = infoNode;
		return;
	    }
	}	
	infoNode.setNext(cur.getNext());
	infoNode.setPrev(cur);
	if (cur.getNext() != null)
	    cur.getNext().setPrev(infoNode);
	cur.setNext(infoNode);

    }

/**
 * Removes an item form the list.
 *
 * @return true if the item was removed, false otherwise.
 * @param accountName the account owner's name of the card to be removed.
 * @param issuedCompanye the company which issued the card to be removed.
 * Big-O value: O(n), because in the worst case, all items in the lsit must be accessed.
 */
    public boolean removeCardInfo(String accountName, String issuedCompany){
	if (head == null)
	    return false;
	if (cur.getInfo().getName().compareToIgnoreCase(accountName) >= 0){
	    cur = head;
	    curPos = 0;
	}
	int x = 0;
	do {
	    if (x == 0)
		x++;
	    else {
		cur = cur.getNext();
		curPos++;
	    }
	    if ( (cur.getInfo().getName().equals(accountName)) && (cur.getInfo().getCompany().equals(issuedCompany)) ) {
		if (cur == head) {
		    head = head.getNext();
		    head.setPrev(null);
		    return true;
		}
		if (cur == tail) {
		    tail = tail.getPrev();
		    tail.setNext(null);
		    return true;
		} 
		cur.getPrev().setNext(cur.getNext());
		cur.getNext().setPrev(cur.getPrev());
		cur = cur.getNext();
		return true;
	    }
	} while(cur.getNext() != null );
	cur = head;
	curPos = 0;
	return false;
    }

/**
 * Displays all items in the lsit to standard output.
 *
 * Big-O value: O(n), because  all items in the lsit must be accessed.
 */

    public void displayAll(){
	if (head == null) {
	    System.out.println("No entries found.");
	    return;
	}
	System.out.println(toString());
    }
	 
/**
 * Displays all cards associated with a certain person.
 *
 * @param name: the name of the person whose cards should be displayed.
 * Big-O value: O(n), because in the worst case, all items in the list must be accessed.
 */
    public void displayByPerson(String name) {
	if (head == null) {
	    return;
	}
	if (cur.getInfo().getName().compareToIgnoreCase(name) >= 0){
	    cur = head;
	    curPos = 0;
	}
	CardList temp = new CardList();
	while (cur != null){
	    if (cur.getInfo().getName().compareToIgnoreCase(name) == 0){
		do {
		    temp.insertCardInfo(cur.getInfo());
		    cur = cur.getNext();
		    curPos++;
		}while ( (cur != null) && (cur.getInfo().getName().compareToIgnoreCase(name) == 0) );
		temp.displayAll();
		cur = head;
		curPos = 0;
		return;
	    }
	    cur = cur.getNext();
	}
	cur = head;
	curPos = 0;
    }

/**
 * Displays all cards associated with a certain company.
 *
 * @param company: the name of the comapny whose cards should be displayed.
 * Big-O value: O(n), because all items in the list must be accessed.
 */
    public void displayByCompany(String company) {
	CardList temp = new CardList();
	cur = head;
	curPos = 0;
	while (true){
	    if (cur.getInfo().getCompany().compareToIgnoreCase(company) == 0)
		temp.insertCardInfo(cur.getInfo());
	    if (cur == tail)
		break;
	    cur = cur.getNext();
	    curPos++;
	}
	temp.displayAll();
    }

/**
 * Displays all cards associated with a certain status code.
 *
 * @param status: the status which cards should have if they are to be displaed.
 * Big-O value: O(n), because all items in the list must be accessed.
 */
    public void displayByStatus(int status) {
	CardList temp = new CardList();
	cur = head;
	curPos = 0;
	while (true){
	    if (cur.getInfo().getStatus() >= status)
		temp.insertCardInfo(cur.getInfo());
	    if (cur == tail)
		break;
	    cur = cur.getNext();
	    curPos++;
	}
	temp.displayAll();
    }

/**
 * Displays all cards with a balance greater than or equal to a given balance.
 *
 * @param balance: cards with a balance >= @param will be displayed.
 * Big-O value: O(n), because all items in the list must be accessed.
 */
    public void displayByBalance(double balance) {
	CardList temp = new CardList();
	cur = head;
	curPos = 0;
	while (true){
	    if (cur.getInfo().getBalance() >= balance)
		temp.insertCardInfo(cur.getInfo());
	    if (cur == tail)
		break;
	    cur = cur.getNext();
	    curPos++;
	}
	temp.displayAll();
    }

/**
 * Displays the first item in the list.

 * Big-O value: O(1), because the same number of calls is required, regardless of the length of the lsit.
 */
    public void displayTop() {
	cur = head;
	curPos = 0;
	if (cur == null){
	    System.out.println("\nNo entries in this list.");
	    return;
	}
	System.out.println(cur.dataToString());
    }
    
/**
 * Displays the next item in the list.

 * Big-O value: O(1), because the same number of calls is required, regardless of the length of the lsit.
 */
    public void displayNext() {
	if (cur.getNext() == null){
	    System.out.println("\nNo next enty available.");
	    return;
	}
	cur = cur.getNext();
	curPos++;
	System.out.println(cur.dataToString());
    }

/**
 * Displays the previous item in the list.

 * Big-O value: O(1), because the same number of calls is required, regardless of the length of the lsit.
 */
    public void displayPrevious() {
	if (cur.getPrev() == null){
	    System.out.println("\nNo previous entry available.");
	    return;
	}
	cur = cur.getPrev();
	curPos--;
	System.out.println(cur.dataToString());
    }

}
